package com.william.jdbcplus.core.dialects.fill.impl;

import com.william.jdbcplus.core.crud.CrudConfig;
import com.william.jdbcplus.core.crud.impl.ShardCrud;
import com.william.jdbcplus.core.dialects.fill.IFill;
import com.william.jdbcplus.common.entity.Entity;
import com.william.jdbcplus.core.toolkit.StringPool;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.integration.redis.util.RedisLockRegistry;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;

public class NumberFill implements IFill {

    private static final String redisKeyField = "NumberField";

    /**
     * 获取redis主键
     *
     * @param entityClass
     * @param config
     * @param <M>
     * @return
     */
    private <M extends Entity> String getRedisKey(Class<M> entityClass, String fieldName, CrudConfig config) {
        String redisPrimaryKey = redisKeyField + StringPool.DOT + entityClass.getName() + StringPool.DOT + fieldName + StringPool.DOT + config.getDsURL();
        return redisPrimaryKey;
    }

    @Override
    public <M extends Entity> Object getValue(Class<M> entityClass, String fieldName, CrudConfig config) {
        String redisPrimaryKey = getRedisKey(entityClass, fieldName, config);
        Long result = null;

        RedisLockRegistry redisLock = config.getRedisLock();
        Lock lock = redisLock.obtain(redisPrimaryKey);

        try {
            lock.lockInterruptibly();

            RedisAtomicLong counter = new RedisAtomicLong(redisPrimaryKey, config.getRedisTemplate().getConnectionFactory());
            if (counter.get() == 0) {
                Long maxId = ShardCrud.getInstance().queryMaxId(entityClass, config);
                if (maxId != null) {
                    counter.set(maxId);
                }
            }
            result = counter.incrementAndGet();
        } catch (Exception ex) {
        } finally {
            lock.unlock();
        }

        return result;
    }

    @Override
    public <M extends Entity> List<?> getValueList(Class<M> entityClass, String fieldName, int count, CrudConfig config) {
        String redisPrimaryKey = getRedisKey(entityClass, fieldName, config);
        List<Long> result = new ArrayList<>();

        RedisLockRegistry redisLock = config.getRedisLock();
        Lock lock = redisLock.obtain(redisPrimaryKey);

        try {
            lock.lockInterruptibly();

            RedisAtomicLong counter = new RedisAtomicLong(redisPrimaryKey, config.getRedisTemplate().getConnectionFactory());
            if (counter.get() == 0) {
                Long maxId = ShardCrud.getInstance().queryMaxId(entityClass, config);
                if (maxId != null) {
                    counter.set(maxId);
                }
            }

            if (count > 0) {
                Long pkMax = counter.get();
                counter.set(pkMax + count);
                for (int i = 1; i <= count; i++) {
                    result.add(pkMax + i);
                }
            }
        } catch (Exception ex) {

        } finally {
            lock.unlock();
        }

        return result;
    }

}
